package com.dsl.perfs;

import com.dsl.ast.EasyDSLLexer;
import com.dsl.ast.EasyDSLParser;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ExprEvalutorHelper {

    private static ConcurrentHashMap<String, ExprNode> exprAstClassMap = new ConcurrentHashMap();

    public static boolean exec(String expr, Map<String, Boolean> params) {
        ExprNode root = exprAstClassMap.get(expr);
        if ( root == null ) {
            synchronized (expr.intern()) {
                if ( root == null ) {
                    EasyDSLLexer lexer = new EasyDSLLexer(new ANTLRInputStream(expr));
                    /* 根据lexer 创建token stream */
                    CommonTokenStream tokens = new CommonTokenStream(lexer);
                    /* 根据token stream 创建 parser */
                    EasyDSLParser paser = new EasyDSLParser(tokens);
                    /* 为parser添加一个监听器 */
                    EasyDSLListener listener = new EasyDSLListener();
                    paser.addParseListener(listener);
                    /* 匹配 line, 监听器会记录结果 */
                    paser.line();

                    root = listener.getResult();

                    exprAstClassMap.put(expr, root);
                }
            }
        }

        return ExprEvalutorHelper.evalute(root, params);
    }

    public static boolean evalute(ExprNode cur, Map<String, Boolean> params) {
        if ( cur.type == ExprType.ID ) {
            return params.get(cur.id);
        } else {
            if ( cur.type == ExprType.AND ) {
                boolean leftRes = evalute(cur.left, params);
                // *) 剪枝优化
                if ( leftRes == false ) return false;
                boolean rightRes = evalute(cur.right, params);
                return leftRes && rightRes;
            } else {
                // *) 如果为 OR
                boolean leftRes = evalute(cur.left, params);
                // *) 剪枝优化
                if ( leftRes == true ) return true;
                boolean rightRes = evalute(cur.right, params);
                return leftRes || rightRes;
            }
        }
    }

}
